import functools
from typing import List, Set, Tuple

from chernc.treediff.gumtree.matchers.heuristic.gt.abstract_subtree_matcher import AbstractSubtreeMatcher
from chernc.treediff.gumtree.matchers.heuristic.gt.mapping_comparators import MappingComparators
from chernc.treediff.gumtree.matchers.mapping import Mapping
from chernc.treediff.gumtree.tree.tree import TreeLike

class GreedySubtreeMatcher(AbstractSubtreeMatcher):
    def __init__(self):
        super().__init__()

    def handle_ambiguous_mappings(self, ambiguous_mappings: List[Tuple[Set[TreeLike], Set[TreeLike]]]):
        comparator = MappingComparators.FullMappingComparator(self.mappings)
        ambiguous_mappings.sort(key=functools.cmp_to_key(AmbiguousMappingsComparator()))
        for pair in ambiguous_mappings:
            candidates = self.convert_to_mappings(pair)
            candidates.sort(key=functools.cmp_to_key(comparator))
            for mapping in candidates:
                if self.mappings.are_both_unmapped(mapping.src, mapping.dst):
                    self.mappings.add_mapping_recursively(mapping.src, mapping.dst)

    @staticmethod
    def convert_to_mappings(ambiguous_mapping: Tuple[Set[TreeLike], Set[TreeLike]]) -> List['Mapping']:
        mappings = []
        for src in ambiguous_mapping[0]:
            for dst in ambiguous_mapping[1]:
                mappings.append(Mapping(src, dst))
        return mappings

class AmbiguousMappingsComparator:
    def __call__(self, m1: Tuple[Set[TreeLike], Set[TreeLike]], m2: Tuple[Set[TreeLike], Set[TreeLike]]) -> int:
        s1 = max(m1[0], key=lambda t: t.get_metrics().size).get_metrics().size
        s2 = max(m2[0], key=lambda t: t.get_metrics().size).get_metrics().size
        return s2 - s1